<template>
  <div
    class="edit-wrapper"
    ref="editWrapper"
    :style="styles"
    :data-component-id="id"
    @mousedown="startMove"
    @click="onItemClick(id)"
    :class="{ active: active, hidden: hidden }"
  >
    <slot></slot>
    <div class="resizers">
      <div
        class="resizer top-left"
        @mousedown.stop="startResize('top-left')"
      ></div>
      <div
        class="resizer top-right"
        @mousedown.stop="startResize('top-right')"
      ></div>
      <div
        class="resizer bottom-left"
        @mousedown.stop="startResize('bottom-left')"
      ></div>
      <div
        class="resizer bottom-right"
        @mousedown.stop="startResize('bottom-right')"
      ></div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, computed, ref, nextTick } from 'vue';
import { pick } from 'lodash-es';
type ResizeDirection =
  | 'top-left'
  | 'top-right'
  | 'bottom-left'
  | 'bottom-right';
interface OriginalPositions {
  left: number;
  right: number;
  top: number;
  bottom: number;
}

export default defineComponent({
  props: {
    id: {
      type: String,
      required: true,
    },
    active: {
      type: Boolean,
      default: false,
    },
    hidden: {
      type: Boolean,
      default: false,
    },
    props: {
      type: Object,
    },
  },
  emits: ['set-active', 'update-position'],
  setup(props, context) {
    const editWrapper = ref<null | HTMLElement>(null);
    const onItemClick = (id: string) => {
      context.emit('set-active', id);
    };
    const gap = {
      x: 0,
      y: 0,
    };
    let isMoving = false;
    const styles = computed(() =>
      pick(props.props, ['position', 'top', 'left', 'width', 'height'])
    );
    const caculateMovePosition = (e: MouseEvent) => {
      const container = document.getElementById('canvas-area') as HTMLElement;
      const left = e.clientX - gap.x - container.offsetLeft;
      const top = e.clientY - gap.y - container.offsetTop + container.scrollTop;
      return {
        left,
        top,
      };
    };
    const caculateSize = (
      direction: ResizeDirection,
      e: MouseEvent,
      positions: OriginalPositions
    ) => {
      const { clientX, clientY } = e;
      const { left, right, top, bottom } = positions;
      const container = document.getElementById('canvas-area') as HTMLElement;
      const rightWidth = clientX - left;
      const leftWidth = right - clientX;
      const bottomHeight = clientY - top;
      const topHeight = bottom - clientY;
      const topOffset = clientY - container.offsetTop + container.scrollTop;
      const leftOffset = clientX - container.offsetLeft;
      switch (direction) {
        case 'top-left':
          return {
            width: leftWidth,
            height: topHeight,
            top: topOffset,
            left: leftOffset,
          };
        case 'top-right':
          return {
            width: rightWidth,
            height: topHeight,
            top: topOffset,
          };
        case 'bottom-left':
          return {
            width: leftWidth,
            height: bottomHeight,
            left: leftOffset,
          };
        case 'bottom-right':
          return {
            width: rightWidth,
            height: bottomHeight,
          };
        default:
          break;
      }
    };
    const startResize = (direction: ResizeDirection) => {
      const currentElement = editWrapper.value as HTMLElement;
      const { left, right, top, bottom } =
        currentElement.getBoundingClientRect();
      const handleMove = (e: MouseEvent) => {
        const size = caculateSize(direction, e, { left, right, top, bottom });
        const { style } = currentElement;
        if (size) {
          style.width = size.width + 'px';
          style.height = size.height + 'px';
          if (size.left) {
            style.left = size.left + 'px';
          }
          if (size.top) {
            style.top = size.top + 'px';
          }
        }
      };
      const handleMouseUp = (e: MouseEvent) => {
        document.removeEventListener('mousemove', handleMove);
        const size = caculateSize(direction, e, { left, right, top, bottom });
        context.emit('update-position', { ...size, id: props.id });
        nextTick(() => {
          document.removeEventListener('mouseup', handleMouseUp);
        });
      };
      document.addEventListener('mousemove', handleMove);
      document.addEventListener('mouseup', handleMouseUp);
    };
    const startMove = (e: MouseEvent) => {
      const currentElement = editWrapper.value;
      if (currentElement) {
        const { left, top } = currentElement.getBoundingClientRect();
        gap.x = e.clientX - left;
        gap.y = e.clientY - top;
        console.log(gap);
      }
      const handleMove = (e: MouseEvent) => {
        const { left, top } = caculateMovePosition(e);
        isMoving = true;
        console.log(left, top);
        if (currentElement) {
          currentElement.style.top = top + 'px';
          currentElement.style.left = left + 'px';
        }
      };
      const handleMouseUp = (e: MouseEvent) => {
        document.removeEventListener('mousemove', handleMove);
        if (isMoving) {
          const { left, top } = caculateMovePosition(e);
          context.emit('update-position', { left, top, id: props.id });
          isMoving = false;
        }
        nextTick(() => {
          document.removeEventListener('mouseup', handleMouseUp);
        });
      };
      document.addEventListener('mousemove', handleMove);
      document.addEventListener('mouseup', handleMouseUp);
    };
    return {
      onItemClick,
      styles,
      editWrapper,
      startMove,
      startResize,
    };
  },
});
</script>

<style>
.edit-wrapper {
  padding: 0px;
  cursor: pointer;
  border: 1px solid transparent;
  user-select: none;
  box-sizing: content-box !important;
}
.edit-wrapper > * {
  position: static !important;
  width: 100% !important;
  height: 100% !important;
  top: auto !important;
  left: auto !important;
}
.edit-wrapper:hover {
  border: 1px dashed #ccc;
}
.edit-wrapper.hidden {
  display: none;
}
.edit-wrapper.active {
  border: 1px solid #1890ff;
  user-select: none;
  z-index: 1500;
}
.edit-wrapper .resizers {
  display: none;
}
.edit-wrapper.active .resizers {
  display: block;
}
.edit-wrapper.active .resizers .resizer {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid #1890ff;
  position: absolute;
}
.edit-wrapper .resizers .resizer.top-left {
  left: -5px;
  top: -5px;
  cursor: nwse-resize;
}
.edit-wrapper .resizers .resizer.top-right {
  right: -5px;
  top: -5px;
  cursor: nesw-resize;
}
.edit-wrapper .resizers .resizer.bottom-left {
  left: -5px;
  bottom: -5px;
  cursor: nesw-resize;
}
.edit-wrapper .resizers .resizer.bottom-right {
  right: -5px;
  bottom: -5px;
  cursor: nwse-resize;
}
</style>
